package com.dawn.iiotgateway.daemon;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
//import org.eclipse.milo.opcua.sdk.client.api.nodes.Node;
import org.eclipse.milo.opcua.sdk.client.nodes.UaNode;
import org.eclipse.milo.opcua.stack.client.DiscoveryClient;
//import org.eclipse.milo.opcua.stack.client.UaTcpStackClient;
import org.eclipse.milo.opcua.stack.core.Identifiers;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.builtin.*;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription;

import java.util.Arrays;
import java.util.List;

@Slf4j
@Data
public class OpcUtil {

    private static final OpcUaClient client;

    static {
        client=createClient("opc.tcp://LshHwNotebook:53530/OPCUA/SimulationServer");
    }

    public static void main(String[] args) throws Exception {
        browseRoot();
        writeValue("通道 2.设备 1.string","你好啊");
        readValue("通道 2.设备 1.string");
    }



    public static OpcUaClient createClient(String endPointUrl){
        try {
            //获取安全策略
            List<EndpointDescription>  endpointDescription = DiscoveryClient.getEndpoints(endPointUrl).get();
            //过滤出一个自己需要的安全策略
            EndpointDescription endpoint = endpointDescription.stream()
                    .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
                    .findFirst().orElse(null);
            // 设置配置信息
            OpcUaClientConfig config = OpcUaClientConfig.builder()
                    // opc ua 自定义的名称
                    .setApplicationName(LocalizedText.english("plc"))
                    // 地址
                    .setApplicationUri(endPointUrl)
                    // 安全策略等配置
                    .setEndpoint(endpoint)
                    //  .setIdentityProvider(new UsernameProvider("tarzan","123456"))
                    //等待时间
                    .setRequestTimeout(UInteger.valueOf(1000))
                    .build();
            // 准备连接
            OpcUaClient opcClient =OpcUaClient.create(config);
            //开启连接
            opcClient.connect().get();
            return opcClient;
        } catch (Exception e) {
            //log.error("======== opc connection fail ========");
        }
        return null;
    }
    /**
     * 获取节点信息
     *
     * @param identifier
     * @throws Exception
     */
    public static void browseNode(String identifier) throws Exception {
        NodeId nodeId =Identifiers.ObjectsFolder;
        if(StringUtils.isNotBlank(identifier)){
            nodeId = new NodeId(2, identifier);
        }
        List<UaNode> nodes = (List<UaNode>) client.getAddressSpace().browseNodes(nodeId);
        for (UaNode node : nodes) {
//            log.info("identifier:"+node.getNodeId().getIdentifier());
        }

    }

    public static void browseRoot() throws Exception {
        browseNode(null);
    }


    /**
     * 读取值
     *
     * @param identifier
     * @throws Exception
     */
    public static void readValue(String identifier) throws Exception {
        NodeId nodeId = new NodeId(2, identifier);
        DataValue value = client.readValue(0.0, TimestampsToReturn.Both, nodeId).get();
//        log.info("数据读取："+value.getValue().getValue().toString());
    }


    /**
     * 写入值
     *
     * @param identifier
     * @param value
     * @throws Exception
     */
    public static void writeValue(String identifier, Object value) throws Exception {
        //创建变量节点
        NodeId nodeId = new NodeId(2, identifier);
        //创建Variant对象和DataValue对象
        Variant v = new Variant(value);
        DataValue dataValue = new DataValue(v, null, null);
        StatusCode statusCode = client.writeValue(nodeId, dataValue).get();
        if(statusCode.isGood()){
//            log.info("数据写入成功");
        }else {
//            log.error("数据写入失败");
        }
    }


}

